{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-aria/gridlist';
import ChevronRight from '@spectrum-icons/workflow/ChevronRight';
import collectionsDocs from 'docs:@react-types/shared/src/collections.d.ts';
import selectionDocs from 'docs:@react-stately/selection';
import statelyDocs from 'docs:@react-stately/list';
import focusDocs from 'docs:@react-aria/focus';
import checkboxDocs from 'docs:@react-aria/checkbox';
import utilsDocs from 'docs:@react-aria/utils';
import {HeaderInfo, FunctionAPI, TypeContext, InterfaceType, TypeLink, PageDescription} from '@react-spectrum/docs';
import {Keyboard} from '@react-spectrum/text';
import packageData from '@react-aria/gridlist/package.json';
import Anatomy from './anatomy.svg';

---
category: Collections
keywords: [list, aria, grid]
---

# useGridList

{/* Description had a misspelling in released version. Revert this on the next release. */}
{/* <PageDescription>{docs.exports.useGridList.description}</PageDescription> */}
<PageDescription>Provides the behavior and accessibility implementation for a list component with interactive children. A grid list displays data in a single column and enables a user to navigate its contents via directional navigation keys.</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['useGridList', 'useGridListItem', 'useGridListSelectionCheckbox']}
  sourceData={[
    {type: 'W3C', url: 'https://www.w3.org/WAI/ARIA/apg/patterns/grid/'}
  ]} />

## API

<FunctionAPI function={docs.exports.useGridList} links={docs.links} />
<FunctionAPI function={docs.exports.useGridListItem} links={docs.links} />
<FunctionAPI function={docs.exports.useGridListSelectionCheckbox} links={docs.links} />

## Features

A list can be built using [&lt;ul&gt;](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul) or [&lt;ol&gt;](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ol) HTML elements, but does not support any user interactions.
HTML lists are meant for static content, rather than lists with rich interactions like focusable elements within rows, keyboard navigation, row selection, etc.
`useGridList` helps achieve accessible and interactive list components that can be styled as needed.

* **Item selection** – Single or multiple selection, with optional checkboxes, disabled rows, and both `toggle` and `replace` selection behaviors.
* **Interactive children** – List items may include interactive elements such as buttons, checkboxes, menus, etc.
* **Actions** – Items support optional row actions such as navigation via click, tap, double click, or <Keyboard>Enter</Keyboard> key.
* **Async loading** – Support for loading items asynchronously, with infinite and virtualized scrolling.
* **Keyboard navigation** – List items and focusable children can be navigated using the arrow keys, along with page up/down, home/end, etc. Typeahead, auto scrolling, and selection modifier keys are supported as well.
* **Touch friendly** – Selection and actions adapt their behavior depending on the device. For example, selection is activated via long press on touch when item actions are present.
* **Accessible** – Follows the [ARIA grid pattern](https://www.w3.org/WAI/ARIA/apg/patterns/grid/), with additional selection announcements via an ARIA live region. Extensively tested across many devices and [assistive technologies](../quality#supported-screen-readers) to ensure announcements and behaviors are consistent.

**Note**: Use `useGridList` when your list items may contain interactive elements such as buttons, checkboxes, menus, etc. within them. If your list items contain only static content such as text and images, then consider using [useListBox](../ListBox/useListBox.html) instead for a slightly better screen reader experience (especially on mobile).

## Anatomy

<Anatomy role="img" aria-label="Anatomy diagram of a list container, consisting of multiple list items. Each list item contains a selection checkbox, a list item row, and a list item cell." />

A grid list consists of a container element, with rows of data inside. The rows within a list may contain focusable elements or plain text content.
If the list supports row selection, each row can optionally include a selection checkbox.

The <TypeLink links={docs.links} type={docs.exports.useGridList} /> and <TypeLink links={docs.links} type={docs.exports.useGridListItem} /> hooks handle keyboard, mouse, and other interactions to support
row selection, in list navigation, and overall focus behavior. Those hooks handle exposing the list and its contents to assistive technology using ARIA. <TypeLink links={docs.links} type={docs.exports.useGridListSelectionCheckbox} /> handles row selection and associating each checkbox with its respective rows
for assistive technology.

`useGridList` returns props that you should spread onto the list container element:

<TypeContext.Provider value={docs.links}>
  <InterfaceType properties={docs.links[docs.exports.useGridList.return.id].properties} />
</TypeContext.Provider>

`useGridListItem` returns props for an individual option and its children, along with states you can use for styling:

<TypeContext.Provider value={docs.links}>
  <InterfaceType properties={docs.links[docs.exports.useGridListItem.return.id].properties} />
</TypeContext.Provider>

State is managed by the <TypeLink links={statelyDocs.links} type={statelyDocs.exports.useListState} />
hook from `@react-stately/list`. The state object should be passed as an option to each of the above hooks where applicable.

Note that an `aria-label` or `aria-labelledby` must be passed to the list to identify the element to assistive technology.

## State management

`useGridList` requires knowledge of the rows in the list in order to handle keyboard
navigation and other interactions. It does this using
the <TypeLink links={collectionsDocs.links} type={collectionsDocs.exports.Collection} />
interface, which is a generic interface to access sequential unique keyed data. You can
implement this interface yourself, e.g. by using a prop to pass a list of item objects,
but <TypeLink links={statelyDocs.links} type={statelyDocs.exports.useListState} /> from
`@react-stately/list` implements a JSX based interface for building collections instead.
See [Collection Components](v3:collections.html) for more information.

In addition, <TypeLink links={statelyDocs.links} type={statelyDocs.exports.useListState} />
manages the state necessary for multiple selection and exposes
a <TypeLink links={selectionDocs.links} type={selectionDocs.exports.SelectionManager} />,
which makes use of the collection to provide an interface to update the selection state.
For more information, see [Selection](v3:selection.html).

## Example

Lists are [collection components](v3:collections.html) that include rows as child elements.
In this example, we'll use the standard HTML unordered list elements along with hooks from React
Aria for each child. You may also use other elements like `<div>` to render these components as appropriate.
We'll walk through creating the list container and list item, then add some additional behavior such as selection.

The <TypeLink links={docs.links} type={docs.exports.useGridList} /> hook will be used to render the outer most list element. It uses
the <TypeLink links={statelyDocs.links} type={statelyDocs.exports.useListState} /> hook to construct the list's collection of rows,
and manage state such as the focused row and row selection. We'll use the collection to iterate through
the rows of the List and render the relevant components, which we'll define below.

You may notice the extra `<div>` with `gridCellProps` in our example. This is needed because we are following the [ARIA grid pattern](https://www.w3.org/WAI/ARIA/apg/patterns/grid/), which does not allow rows without any child `gridcell` elements.

```tsx example export=true render=false
import {useListState} from '@react-stately/list';
import {mergeProps} from '@react-aria/utils';
import {useRef} from 'react';
import {useFocusRing} from '@react-aria/focus';
import {useGridList, useGridListItem} from '@react-aria/gridlist';

function List(props) {
  let state = useListState(props);
  let ref = useRef<HTMLUListElement | null>(null);
  let { gridProps } = useGridList(props, state, ref);

  return (
    <ul {...gridProps} ref={ref} className="list">
      {[...state.collection].map((item) => (
        <ListItem key={item.key} item={item} state={state} />
      ))}
    </ul>
  );
}

function ListItem({ item, state }) {
  let ref = React.useRef(null);
  let {rowProps, gridCellProps, isPressed} = useGridListItem(
    {node: item},
    state,
    ref
  );

  let {isFocusVisible, focusProps} = useFocusRing();
  let showCheckbox = state.selectionManager.selectionMode !== 'none' && state.selectionManager.selectionBehavior === 'toggle';

  return (
    <li
      {...mergeProps(rowProps, focusProps)}
      ref={ref}
      className={`${isPressed ? 'pressed' : ''} ${isFocusVisible ? 'focus-visible' : ''}`}>
      <div {...gridCellProps}>
        {showCheckbox && <ListCheckbox item={item} state={state} />}
        {item.rendered}
      </div>
    </li>
  );
}
```

Now we can render a basic example list, with multiple selection and interactive children in each item.

```tsx example
import {Item} from "@react-stately/collections";

// Reuse the Button from your component library. See below.
import {Button} from 'your-component-library';

<List aria-label="Example List" selectionMode="multiple" selectionBehavior="replace">
  <Item textValue="Charizard">
    Charizard
    <Button onPress={() => alert(`Info for Charizard...`)}>Info</Button>
  </Item>
  <Item textValue="Blastoise">
    Blastoise
    <Button onPress={() => alert(`Info for Blastoise...`)}>Info</Button>
  </Item>
  <Item textValue="Venusaur">
    Venusaur
    <Button onPress={() => alert(`Info for Venusaur...`)}>Info</Button>
  </Item>
  <Item textValue="Pikachu">
    Pikachu
    <Button onPress={() => alert(`Info for Pikachu...`)}>Info</Button>
  </Item>
</List>
```

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show CSS</summary>

```css
.list {
  padding: 0;
  list-style: none;
  background: var(--page-background);
  border: 1px solid var(--spectrum-global-color-gray-400);
  max-width: 400px;
  min-width: 200px;
  max-height: 250px;
  overflow: auto;
}

.list li {
  padding: 8px;
  outline: none;
  cursor: default;
}

.list li:nth-child(2n) {
  background: var(--spectrum-alias-highlight-hover);
}

.list li.pressed {
  background: var(--spectrum-global-color-gray-200);
}

.list li[aria-selected=true] {
  background: slateblue;
  color: white;
}

.list li.focus-visible {
  outline: 2px solid slateblue;
  outline-offset: -3px;
}

.list li.focus-visible[aria-selected=true] {
  outline-color: white;
}

.list li[aria-disabled] {
  opacity: 0.4;
}

.list [role=gridcell] {
  display: flex;
  align-items: center;
  gap: 4px;
}

.list li button {
  margin-left: auto;
}

/* iOS Safari has a bug that prevents accent-color: white from working. */
@supports not (-webkit-touch-callout: none) {
  .list li input[type=checkbox] {
    accent-color: white;
  }
}
```

</details>

### Adding selection checkboxes

Next, let's add support for selection checkboxes to allow the user to select items explicitly.
This is done using the <TypeLink links={docs.links} type={docs.exports.useGridListSelectionCheckbox} />
hook. It is passed the `key` of the item it is contained within. When the user
checks or unchecks the checkbox, the row will be added or removed from the List's selection.

The `Checkbox` component used in this example is independent and can be used separately from `useGridList`. The code is available below.

```tsx example export=true render=false
import {useGridListSelectionCheckbox} from '@react-aria/gridlist';

// Reuse the Checkbox from your component library. See below for details.
import {Checkbox} from 'your-component-library';

function ListCheckbox({ item, state }) {
  let { checkboxProps } = useGridListSelectionCheckbox({ key: item.key }, state);
  return <Checkbox {...checkboxProps} />;
}
```

The following example shows an example list with multiple selection using checkboxes and the default `toggle` [selection behavior](#selection-behavior).

```tsx example
<List aria-label="List with selection" selectionMode="multiple">
  <Item textValue="Charizard">
    Charizard
    <Button onPress={() => alert(`Info for Charizard...`)}>Info</Button>
  </Item>
  <Item textValue="Blastoise">
    Blastoise
    <Button onPress={() => alert(`Info for Blastoise...`)}>Info</Button>
  </Item>
  <Item textValue="Venusaur">
    Venusaur
    <Button onPress={() => alert(`Info for Venusaur...`)}>Info</Button>
  </Item>
  <Item textValue="Pikachu">
    Pikachu
    <Button onPress={() => alert(`Info for Pikachu...`)}>Info</Button>
  </Item>
</List>
```

And that's it! We now have a fully interactive List component that can support keyboard navigation, single or multiple selection.
In addition, it is fully accessible for screen readers and other assistive technology. See below for more
examples of how to use the List component that we've built.

### Checkbox

The `Checkbox` component is used in the above example for row selection. It is built using the [useCheckbox](../Checkbox/useCheckbox.html) hook, and can be shared with many other components.

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show code</summary>

```tsx example export=true render=false
import {useCheckbox} from '@react-aria/checkbox';
import {useToggleState} from '@react-stately/toggle';

function Checkbox(props) {
  let inputRef = useRef(null);
  let { inputProps } = useCheckbox(
    props,
    useToggleState(props),
    inputRef
  );
  return <input {...inputProps} ref={inputRef} />;
}
```

</details>

### Button

The `Button` component is used in the above example to show how rows can contain interactive elements. It is built using the [useButton](../Button/useButton.html) hook, and can be shared with many other components.

<details>
  <summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show code</summary>

```tsx example export=true render=false
import {useButton} from '@react-aria/button';

function Button(props) {
  let ref = React.useRef(null);
  let {buttonProps} = useButton(props, ref);
  return <button {...buttonProps} ref={ref}>{props.children}</button>;
}
```

</details>

## Usage

### Dynamic collections

So far, our examples have shown static collections, where the data is hard coded.
Dynamic collections, as shown below, can be used when the data comes from an external data source such as an API, or updates over time.
In the example below, the rows are provided to the List via a render function.

```tsx example export=true
function ExampleList(props) {
  let rows = [
    {id: 1, name: 'Games'},
    {id: 2, name: 'Program Files'},
    {id: 3, name: 'bootmgr'},
    {id: 4, name: 'log.txt'}
  ];

  return (
    <List aria-label="Example dynamic collection List" selectionMode="multiple" items={rows} {...props}>
      {item => (
        <Item textValue={item.name}>
          {item.name}
          <Button onPress={() => alert(`Info for ${item.name}...`)}>
            Info
          </Button>
        </Item>
      )}
    </List>
  );
}
```

### Single selection

By default, `useListState` doesn't allow row selection but this can be enabled using the `selectionMode` prop. Use `defaultSelectedKeys` to provide a default set of selected rows.
Note that the value of the selected keys must match the `key` prop of the row.

The example below enables single selection mode, and uses `defaultSelectedKeys` to select the row with key equal to "2".
A user can click on a different row to change the selection, or click on the same row again to deselect it entirely.

```tsx example
// Using the example above
<ExampleList aria-label="List with single selection" selectionMode="single" selectionBehavior="replace" defaultSelectedKeys={[2]} />
```

### Multiple selection

Multiple selection can be enabled by setting `selectionMode` to `multiple`.

```tsx example
<ExampleList aria-label="List with multiple selection" selectionMode="multiple" defaultSelectedKeys={[2, 4]} />
```

### Disallow empty selection

`useGridList` also supports a `disallowEmptySelection` prop which forces the user to have at least one row in the List selected at all times.
In this mode, if a single row is selected and the user presses it, it will not be deselected.

```tsx example
<ExampleList aria-label="List with disallowed empty selection" selectionMode="multiple" defaultSelectedKeys={[2]} disallowEmptySelection />
```

### Controlled selection

To programmatically control row selection, use the `selectedKeys` prop paired with the `onSelectionChange` callback. The `key` prop from the selected rows will
be passed into the callback when the row is pressed, allowing you to update state accordingly.

```tsx example export=true
function PokemonList(props) {
  let rows = [
    {id: 1, name: 'Charizard'},
    {id: 2, name: 'Blastoise'},
    {id: 3, name: 'Venusaur'},
    {id: 4, name: 'Pikachu'}
  ];

  let [selectedKeys, setSelectedKeys] = React.useState(new Set([2]));

  return (
    <List aria-label="List with controlled selection" items={rows} selectionMode="multiple" selectedKeys={selectedKeys} onSelectionChange={setSelectedKeys} {...props}>
      {item => <Item>{item.name}</Item>}
    </List>
  );
}
```

### Disabled rows

You can disable specific rows by providing an array of keys to `useListState` via the `disabledKeys` prop. This will disable all interactions on disabled rows,
unless the `disabledBehavior` prop is used to change this behavior.
Note that you are responsible for the styling of disabled rows, however, the selection checkbox will be automatically disabled.

```tsx example
// Using the example above
<PokemonList aria-label="List with disabled rows" selectionMode="multiple" disabledKeys={[3]} />
```

When `disabledBehavior` is set to `selection`, interactions such as focus, dragging, or actions can still be performed on disabled rows.

```tsx example
<PokemonList aria-label="List with selection disabled for disabled rows" selectionMode="multiple" disabledKeys={[3]} disabledBehavior="selection" />
```

### Selection behavior

By default, `useGridList` uses the `"toggle"` selection behavior, which behaves like a checkbox group: clicking, tapping, or pressing the <Keyboard>Space</Keyboard> or <Keyboard>Enter</Keyboard> keys toggles selection for the focused row. Using the arrow keys moves focus but does not change selection. The `"toggle"` selection mode is often paired with a checkbox in each row as an explicit affordance for selection.

When `selectionBehavior` is set to `"replace"`, clicking a row with the mouse replaces the selection with only that row. Using the arrow keys moves both focus and selection. To select multiple rows, modifier keys such as <Keyboard>Ctrl</Keyboard>, <Keyboard>Cmd</Keyboard>, and <Keyboard>Shift</Keyboard> can be used. On touch screen devices, selection always behaves as toggle since modifier keys may not be available.

These selection styles implement the behaviors defined in [Aria Practices](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/#keyboardinteraction).

```tsx example
<PokemonList aria-label="List with replace selection behavior" selectionMode="multiple" selectionBehavior="replace" />
```

### Row actions

`useGridList` supports row actions via the `onAction` prop, which is useful for functionality such as navigation. When nothing is selected, the list performs actions by default when clicking or tapping a row.
Items may be selected using the checkbox, or by long pressing on touch devices. When at least one item is selected, the list is in selection mode, and clicking or tapping a row toggles the selection. Actions may also
be triggered via the <Keyboard>Enter</Keyboard> key, and selection using the <Keyboard>Space</Keyboard> key.

This behavior is slightly different when `selectionBehavior="replace"`, where single clicking selects the row and actions are performed via double click. Touch and keyboard behaviors are unaffected.

```tsx example
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 24 }}>
  <ExampleList aria-label="Checkbox selection list with row actions" selectionMode="multiple" selectionBehavior="toggle" onAction={key => alert(`Opening item ${key}...`)} />
  <ExampleList aria-label="Highlight selection list with row actions" selectionMode="multiple" selectionBehavior="replace" onAction={key => alert(`Opening item ${key}...`)} />
</div>
```

### Links

Items in a GridList may also be links to another page or website. This can be achieved by passing the `href` prop to the `<Item>` component. Links behave the same way as described above for row actions depending on the `selectionMode` and `selectionBehavior`.

```tsx example
<List aria-label="Links" selectionMode="multiple">
  <Item href="https://adobe.com/" target="_blank">Adobe</Item>
  <Item href="https://apple.com/" target="_blank">Apple</Item>
  <Item href="https://google.com/" target="_blank">Google</Item>
  <Item href="https://microsoft.com/" target="_blank">Microsoft</Item>
</List>
```

```css hidden
.list li[data-href] {
  cursor: pointer;
}
```

#### Client side routing

The `<Item>` component works with frameworks and client side routers like [Next.js](https://nextjs.org/) and [React Router](https://reactrouter.com/en/main). As with other React Aria components that support links, this works via the <TypeLink links={utilsDocs.links} type={utilsDocs.exports.RouterProvider} /> component at the root of your app. See the [framework setup guide](../frameworks) to learn how to set this up.

### Asynchronous loading

This example uses the [useAsyncList](../useAsyncList.html) hook to handle asynchronous loading of data from a server. You may additionally want to display a spinner to indicate the loading state to the user, or support features like infinite scroll to load more data.

```tsx example
import {useAsyncList} from '@react-stately/data';

function AsyncList() {

  let list = useAsyncList({
    async load({signal, cursor}) {
      if (cursor) {
        cursor = cursor.replace(/^http:\/\//i, 'https://');
      }

      let res = await fetch(cursor || `https://swapi.py4e.com/api/people/?search=`, {signal});
      let json = await res.json();

      return {
        items: json.results,
        cursor: json.next
      };
    }
  });

  return (
    <List
      selectionMode="multiple"
      aria-label="Async loading ListView example"
      items={list.items}>
      {(item) => (
        <Item key={item.name}>{item.name}</Item>
      )}
    </List>
  );
}
```

## Internationalization

`useGridList` handles some aspects of internationalization automatically.
For example, type to select is implemented with an
[Intl.Collator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Collator)
for internationalized string matching, and keyboard navigation is mirrored in right-to-left languages.
You are responsible for localizing all text content within the List.

### RTL

In right-to-left languages, the list layout should be mirrored. The row contents should be ordered from right to left and the row's text alignment should be inverted. Ensure that your CSS accounts for this.
